﻿using System.Collections.Generic;
using System.Drawing;
using System.Collections;

namespace BarStructures
{
    public class Model : IDrawableModel
    {
        private List<Node> nodes = new List<Node>();

        private List<Bar> bars = new List<Bar>();

        private string name = "unnamed";

        private int uniqueNodeIndexCounter = 0;

        private bool envelopeHasBeenChanged = false;
        private BoundingBox envelope = new BoundingBox(0, 0, 0, 0);

        private SortedList<int, int> suMap = new SortedList<int, int>();

        public Model()
        {
        }

        public Model(string name)
            : this()
        {
            this.name = name;
        }

        public string GetName()
        {
            return this.name;
        }

        public bool DrawAsFrame { get; set; }

        public Node GetNodeByUniqueIndex(int uniqueIndex)
        {
            //можно использовать бинарный поиск, так как uniqueIndex всегда возрастает
            int i = 0;
            while (i < nodes.Count && nodes[i].UniqueIndex != uniqueIndex)
                i++;
            if (i != nodes.Count)
                return nodes[i];
            else
                return null;
        }

        public Node GetNodeBySystemIndex(int systemIndex)
        {
            int uniqueIndex = suMap[systemIndex];
            return GetNodeByUniqueIndex(uniqueIndex);
        }

        public void ChangeNodeSystemIndex(Node node, int newSystemIndex)
        {
            suMap[node.SystemIndex] = newSystemIndex;
            node.SystemIndex = newSystemIndex;
        }

        public Bar GetBar(int orderIndex)
        {
            return bars[orderIndex];
        }

        public int GetNodesCount()
        {
            return nodes.Count;
        }

        public int GetBarsCount()
        {
            return bars.Count;
        }

        public void SetAutoSystemIndexes()
        {
            suMap.Clear();
            for (int i = 0; i < nodes.Count; i++)
            {
                nodes[i].SystemIndex = i;
                suMap.Add(i, nodes[i].UniqueIndex);
            }
        }

        #region Node and bar creation

        public Node CreateNode(double x, double y)
        {
            Node node = new Node(x, y, uniqueNodeIndexCounter++);
            nodes.Add(node);
            envelopeHasBeenChanged = true;
            return node;
        }

        public Node CreateNode(double x, double y, int systemIndex)
        {
            Node node = new Node(x, y, uniqueNodeIndexCounter++, systemIndex);
            nodes.Add(node);
            suMap.Add(systemIndex, node.UniqueIndex);
            envelopeHasBeenChanged = true;
            return node;
        }

        public Bar CreateBar(Node nodeOne, Node nodeTwo, BarPhysicalProperties phys)
        {
            Bar bar = new Bar(nodeOne, nodeTwo, phys);
            bars.Add(bar);
            return bar;
        }
        
        #endregion

        #region IDrawableModel Members

        public BoundingBox GetModelEnvelope()
        {
            if (envelopeHasBeenChanged)
            {
                if (nodes.Count > 0)
                {
                    envelope.MinX = nodes[0].X;
                    envelope.MaxX = nodes[0].X;
                    envelope.MinY = nodes[0].Y;
                    envelope.MaxY = nodes[0].Y;
                    for (int i = 1; i < nodes.Count; i++)
                    {
                        if (nodes[i].X < envelope.MinX)
                            envelope.MinX = nodes[i].X;
                        else
                            if (nodes[i].X > envelope.MaxX)
                                envelope.MaxX = nodes[i].X;

                        if (nodes[i].Y < envelope.MinY)
                            envelope.MinY = nodes[i].Y;
                        else
                            if (nodes[i].Y > envelope.MaxY)
                                envelope.MaxY = nodes[i].Y;
                    }
                }
                else
                    envelope = new BoundingBox(0, 0, 0, 0);
            }
            return envelope;
        }

        public void Draw(IDrawBoard d)
        {
            for (int i = 0; i < bars.Count; i++)
                bars[i].Draw(d);
            
            for (int i = 0; i < nodes.Count; i++)
                nodes[i].Draw(d);
        }

        #endregion
    }
}
